package com.byx.imclientutil.netty;

import android.util.Log;

import com.byx.imclientutil.config.ImConnectionStatus;
import com.byx.imclientutil.entity.MessageStatus;
import com.byx.imclientutil.entity.MessageType;
import com.byx.imclientutil.protobuf.ChatMessageProtobuf;

import java.util.UUID;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.util.internal.StringUtil;

/**
 * NettyWebSocketHandler
 *
 * @author Superb
 * @date 2021/2/9 18:24
 */
public class NettyWebSocketHandler extends ChannelInboundHandlerAdapter {
    private static final String TAG = NettyWebSocketHandler.class.getSimpleName();
    private NettyWebSocketClientImpl imService;


    public NettyWebSocketHandler(NettyWebSocketClientImpl imService) {
        this.imService = imService;
    }

    /**
     * Calls {@link ChannelHandlerContext#fireChannelInactive()} to forward
     * to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
     * <p>
     * Sub-classes may override this method to change behavior.
     *
     * @param ctx
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        Log.d(TAG, "channelInactive: "+ctx.channel().localAddress() + "下线");
        Log.w(TAG, "channelInactive() ctx = " + ctx);
        closeChannelAndReconnect(ctx);
    }

    /**
     * Calls {@link ChannelHandlerContext#fireChannelRead(Object)} to forward
     * to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
     * <p>
     * Sub-classes may override this method to change behavior.
     *
     * @param ctx
     * @param msg
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ChatMessageProtobuf.Msg message= (ChatMessageProtobuf.Msg) msg;
        Log.d(TAG, "channelRead() ctx = " + ctx + "\tmsg = " + message);
        int msgType=message.getMessageType();
        switch (msgType){
            case MessageType.SERVER_STATUS_REPORT:
                int statusReport = message.getStatusReport();
                if (statusReport == 1){
                    System.out.println("收到服务端发送状态报告：已发送");
                    imService.callBackMessageStatus(message.getMessageId(), MessageStatus.SUCCEED);
                }else {
                    imService.callBackMessageStatus(message.getMessageId(),MessageStatus.FAILED);
                }
                break;
            default:
                // 其它消息
                // 收到消息后，立马给服务端回一条消息接收状态报告
                ChatMessageProtobuf.Msg receivedReportMsg = buildReceivedReportMsg(message.getMessageId());
                if(receivedReportMsg != null) {
                    imService.sendMessage(receivedReportMsg);
                }
                System.out.println(message);
                imService.getMsgDispatcher().receivedMsg(message);
                break;
        }
    }

    /**
     * Calls {@link ChannelHandlerContext#fireExceptionCaught(Throwable)} to forward
     * to the next {@link ChannelHandler} in the {@link ChannelPipeline}.
     * <p>
     * Sub-classes may override this method to change behavior.
     *
     * @param ctx
     * @param cause
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        Log.e(TAG, "exceptionCaught() ctx = " + ctx + "\tcause = " + cause);
        closeChannelAndReconnect(ctx);
    }

    /**
     * 关闭channel并重连
     * @param ctx
     */
    private void closeChannelAndReconnect(ChannelHandlerContext ctx) {
        Log.d(TAG, "准备关闭channel并重连");
        Channel channel = ctx.channel();
        if(channel != null) {
            channel.close();
        }
        // 回调连接状态
        imService.callbackImServiceConnectStatus(ImConnectionStatus.ConnectFailed);
        // 触发重连
        imService.reconnect(false);
    }

    /**
     * 构建客户端消息接收状态报告
     * @param msgId
     * @return
     */
    private ChatMessageProtobuf.Msg buildReceivedReportMsg(String msgId) {
        if (StringUtil.isNullOrEmpty(msgId)) {
            return null;
        }
        return ChatMessageProtobuf.Msg.newBuilder()
                .setMessageId(UUID.randomUUID().toString())
                .setMessageType(imService.getClientReceivedReportMsgType())
                .setContent(msgId)
                .setTimestamp(System.currentTimeMillis())
                .build();
    }
}
